#ifndef SERIALIZE_H
#define SERIALIZE_H
#include "XmlTool.h"
#include "ByteBuffer.h"
#include "common.h"

#define MAKE_PAIR(value,name) std::make_pair(&value, name)
#define PAIR(value) std::make_pair(&value, #value)
#define SERIAL_1(s,p1) s&PAIR(p1)
#define SERIAL_2(s,p1,p2) SERIAL_1(s,p1)&PAIR(p2)
#define SERIAL_3(s,p1,p2,p3) SERIAL_2(s,p1,p2)&PAIR(p3)
#define SERIAL_4(s,p1,p2,p3,p4) SERIAL_3(s,p1,p2,p3)&PAIR(p4)
#define SERIAL_5(s,p1,p2,p3,p4,p5) SERIAL_4(s,p1,p2,p4)&PAIR(p5)
#define SERIAL_6(s,p1,p2,p3,p4,p5,p6) SERIAL_5(s,p1,p2,p5)&PAIR(p6)

const int Serialize_Save = 1;
const int Serialize_Load = 2;

template <class T>
struct Creator
{
	static T Create()
	{
		static T obj;
		return obj;
	}
    static void Destroy( T &t )
    {

    }
};

template <class T>
struct Creator<T *>
{
	static T *Create()
	{
		T *p = new T;
		return p;
	}
    static void Destroy( T *t )
    {
        delete t;
    }
};

template<typename A>
struct remove_const { typedef A type; };
template<typename A>
struct remove_const<const A> { typedef A type; };

template<typename A>
struct base_type { typedef A type; };
template<typename A>
struct base_type<A*> { typedef A type; };
template<typename A>
struct base_type<A&> { typedef A type; };

template<typename A>
struct class_type { typedef typename remove_const<typename base_type<A>::type>::type type; };

class CSerialize
{
public:
    enum
    {
        Xml_Serialize,
        Bin_Serialize,
    };

    CSerialize() 
    {
        m_lastload = true;
    }
    virtual ~CSerialize() {}
    template <typename T>
    void Save( T &t, const char *name = NULL )
    {
        if( m_type == Bin_Serialize )
            ((CBinSerialize*)this)->Save(t);
        else
            ((CXmlSerialize*)this)->Save(t, name);
    }
    template <typename T>
    bool Load( T &t, const char *name = NULL )
    {
        if( m_type == Bin_Serialize )
            m_lastload = ((CBinSerialize*)this)->Load(t);
        else
            m_lastload = ((CXmlSerialize*)this)->Load(t, name);
        return m_lastload;
    }
    template <typename T>
    void SaveObject( T &t, const char *name = NULL )
    {
        if( m_type == Bin_Serialize )
            ((CBinSerialize*)this)->SaveObject(t);
        else
            ((CXmlSerialize*)this)->SaveObject(t, name);
    }
	template <typename T>
	void SaveObject( T *&t, const char *name = NULL )
	{
		if( m_type == Bin_Serialize )
			((CBinSerialize*)this)->SaveObject(*t);
		else
			((CXmlSerialize*)this)->SaveObject(*t, name);
	}
    template <typename T>
    bool LoadObject( T &t, const char *name = NULL )
    {
        if( m_type == Bin_Serialize )
            m_lastload = ((CBinSerialize*)this)->LoadObject(t);
        else
            m_lastload = ((CXmlSerialize*)this)->LoadObject(t, name);
        return m_lastload;
    }
	template <typename T>
	bool LoadObject( T *&t, const char *name = NULL )
	{
		if( m_type == Bin_Serialize )
			m_lastload = ((CBinSerialize*)this)->LoadObject(*t);
		else
			m_lastload = ((CXmlSerialize*)this)->LoadObject(*t, name);
        return m_lastload;
	}
    bool IsSaving()
    {
        return m_save;
    }
    bool IsLoading()
    {
        return !m_save;
    }
    bool GetLastLoad( )
    {
        return m_lastload;
    }
	virtual const char *GetData( uint32 &datalen ) = 0;
    virtual void SaveToFile( const char *path ) = 0;
    virtual bool LoadFromFile( const char *path ) = 0;
    virtual void SetToBegin( ) = 0;
protected:
    bool m_save;
    int m_type;
    bool m_lastload;
};

class CXmlSerialize:public CSerialize
{
public:
    CXmlSerialize( int type, unsigned int size = 1024, const char *data = NULL ):m_current(NULL)
    {
        m_save = (type==Serialize_Save); 
        m_type = Xml_Serialize;
        m_current = NULL;
        if(data == NULL&&m_save)
        {
            m_current = new TiXmlElement("XmlSerial");
            m_doc.LinkEndChild(m_current);
        }
        else if(!m_save && data!=NULL)
        {
            m_doc.Parse(data);
            m_current = m_doc.RootElement();
        }
        m_last = NULL;
    }
    ~CXmlSerialize()
    {
       // m_doc.SaveFile("save.xml");
    }
    virtual bool LoadFromFile( const char *path )
    {
        if( false == m_doc.LoadFile(path) )
            return false;
        m_current = m_doc.RootElement();
        return true;
    }
    virtual void SetToBegin( )
    {
        m_current = m_doc.RootElement();
        m_last = NULL;
        m_lastload = true;
    }
    virtual void SaveToFile( const char *path )
    {
        FILE *f = fopen( path, "w" );
        unsigned int len = 0;
        const char *data = NULL;
        data = GetData(len);
        fwrite( data, len, 1, f );
        fclose(f);
    }
	virtual const char *GetData( uint32 &datalen )
	{
		static TiXmlPrinter printer;
		printer.Clear();
		m_doc.Accept( &printer );
		const char *result = printer.CStr();
		datalen = printer.Size();
		return result;
	}
    template <typename T>
    void Save( T &t, const char *name )
    {
		char str[32];
		sprintf(str, "%d", t);
        TiXmlElement *elem = new TiXmlElement(name);
        m_current->LinkEndChild(elem);
        elem->LinkEndChild(new TiXmlText(str));
    }
    template <>
    void Save( float &t, const char *name )
    {
        char str[32];
        sprintf(str, "%f", t);
        TiXmlElement *elem = new TiXmlElement(name);
        m_current->LinkEndChild(elem);
        elem->LinkEndChild(new TiXmlText(str));
    }
    template <>
    void Save( const char* &t, const char *name )
    {
        TiXmlElement *elem = new TiXmlElement(name);
        m_current->LinkEndChild(elem);
        elem->LinkEndChild(new TiXmlText(t));
    }
    template <>
    void Save( char* &t, const char *name )
    {
        TiXmlElement *elem = new TiXmlElement(name);
        m_current->LinkEndChild(elem);
        elem->LinkEndChild(new TiXmlText(t));
    }
    template <typename T>
    bool Load( T &t, const char *name )
    {
        TiXmlElement *elem = NULL;
        if( m_last)
            elem = m_last->NextSiblingElement(name);
        else if(!elem && m_current)
            elem = m_current->FirstChildElement(name);
        m_last = elem;
        if(elem)
		{
			const char *txt = elem->GetText();
			if( txt )
            {
				t = atoi(txt);
                return true;
            }
            else
                return false;
		}
        else
            return false;
        
    }
    template <>
    bool Load( float &t, const char *name )
    {
        TiXmlElement *elem = NULL;
        if( m_last)
            elem = m_last->NextSiblingElement(name);
        else if(!elem && m_current)
            elem = m_current->FirstChildElement(name);
        m_last = elem;
        if(elem)
		{
			const char *txt = elem->GetText();
			if( txt )
            {
				t = (float)atof(txt);
                return true;
            }
            else
                return false;
		}
        else
            return false;
        
    }
    template <>
    bool Load( const char* &t, const char *name )
    {
        char *nonconst = const_cast<char*>(t);
        TiXmlElement *elem = NULL;
        if( m_last)
            elem = m_last->NextSiblingElement(name);
        else if(!elem && m_current)
            elem = m_current->FirstChildElement(name);
        m_last = elem;
        if(elem)
		{
			const char *txt = elem->GetText();
			if( txt )
            {
				t = strcpy(nonconst, txt);
                return true;
            }
            else
                return false;
		}
        else
            return false;
    }
    template <>
    bool Load( char* &t, const char *name )
    {
        char *nonconst = const_cast<char*>(t);
        TiXmlElement *elem = NULL;
        if( m_last)
            elem = m_last->NextSiblingElement(name);
        else if(!elem && m_current)
            elem = m_current->FirstChildElement(name);
        m_last = elem;
		if(elem)
		{
			const char *txt = elem->GetText();
			if( txt )
            {
				t = strcpy(nonconst, txt);
                return true;
            }
            else
                return false;
		}
        else 
            return false;   
    }
    template <typename T>
    void SaveObject( T &t, const char *name )
    {
        TiXmlElement *objnode = new TiXmlElement(name);
        m_current->LinkEndChild(objnode);
        m_current = objnode;
        t.Serialize(*this);
        m_current = (TiXmlElement*)objnode->Parent();
    }
    template <typename T>
    bool LoadObject( T &t, const char *name )
    {
        TiXmlElement *elem = NULL;
        if( m_last )
            elem = m_last->NextSiblingElement(name);
        else if( !elem && m_current)
            elem = m_current->FirstChildElement(name);
        if(elem)
        {
            m_current = elem;
            m_last = NULL;
            t.Serialize(*this);
            m_current = (TiXmlElement*)elem->Parent();
            m_last = elem;
            return true;
        }
        else
            return false;
    }
private:
    TiXmlDocument m_doc;
    TiXmlElement *m_current;
    TiXmlElement *m_last;
};

class CBinSerialize:public CSerialize
{
public:
    CBinSerialize( int type, unsigned int size = 1024, const char *data = NULL, int len = 0):m_buffer(size)
    {
        m_save = (type==Serialize_Save); 
        m_type = Bin_Serialize;
        if(data && !m_save)
        {
            m_buffer.append(data, len);
        }
    }
    ~CBinSerialize()
    {

    }
    virtual bool LoadFromFile( const char *path )
    {
        return true;
    }
    virtual void SetToBegin( )
    {
        m_buffer.rpos( 0 );
        m_lastload = true;
    }
    virtual void SaveToFile( const char *path )
    {
        FILE *f = fopen( path, "w" );
        unsigned int len = 0;
        const char *data = GetData(len);
        fwrite( data, len, 1, f );
        fclose(f);
    }
	virtual const char *GetData( uint32 &datalen )
	{
		datalen = m_buffer.wpos();
		return (const char *)m_buffer.contents();
	}
    template <typename T>
    void Save( T &t )
    {
        m_buffer<<t;
    }
    template <typename T>
    bool Load( T &t )
    {
        m_buffer>>t;
        return true;
    }
    template <typename T>
    void SaveObject( T &t )
    {
        t.Serialize(*this);
    }
    template <typename T>
    bool LoadObject( T &t )
    {
        t.Serialize(*this);
        return true;
    }
private:
    ByteBuffer m_buffer;
};

template <class T>
inline CSerialize &operator&(CSerialize &s, std::pair<T*, const char*> &p)
{
	if( s.IsSaving())
		s.SaveObject(*(p.first), p.second);
	else
		s.LoadObject(*(p.first), p.second);
    return s;
}

template <int ARRAY>
inline CSerialize &operator&(CSerialize &s, std::pair<char (*)[ARRAY] , const char*> &p)
{
	char *str = *p.first;
	if( s.IsSaving())
		s.Save(str, p.second);
	else
		s.Load(str, p.second);
	return s;
}

template <>
inline CSerialize &operator&(CSerialize &s, std::pair<std::string *, const char*> &p)
{
	const char *str = p.first->c_str();
	if( s.IsSaving())
		s.Save(str, p.second);
	else
	{
		char buffer[1024] = {0};
		s&std::make_pair(&buffer,p.second);
		*p.first = buffer;
	}
	return s;
}

template <>
inline CSerialize &operator&(CSerialize &s, std::pair<std::wstring *, const char*> &p)
{
	const wchar_t *str = p.first->c_str();
	if( s.IsSaving())
	{
		const char *mbstr = WCharToMB( str );
		s.Save( mbstr, p.second);
	}
	else
	{
		char buffer[1024] = {0};
		s&std::make_pair(&buffer,p.second);
		*p.first = MBToWChar( buffer );
	}
	return s;
}

template <class T>
inline CSerialize &operator&(CSerialize &s, std::pair<std::list<T>* , const char*> &p)
{
	if( s.IsSaving())
	{
		std::list<T>::iterator iter = p.first->begin();
		while( iter != p.first->end() )
		{
			T &obj = *iter;
			s&std::make_pair(&obj, p.second);
			iter++;
		}
	}
	else
	{
        while( true )
        {
            T obj = Creator<T>::Create();
            s&std::make_pair(&obj, p.second);
            if( s.GetLastLoad() == false )
            {
                Creator<T>::Destroy( obj );
                break;
            }
            p.first->push_back( obj );
        }
	}
	return s;
}

template <class Key, class Value>
inline CSerialize &operator&(CSerialize &s, std::pair<std::map<Key,Value>* , const char*> &p)
{
	char keyNameBuf[128] = {0}, valueNameBuf[128] = {0};
	strcpy( keyNameBuf, p.second );
	strcat( keyNameBuf, "Key" );
	strcpy( valueNameBuf, p.second );
	strcat( valueNameBuf, "Value" );
	const char *keyName = keyNameBuf;
	const char *valueName = valueNameBuf;

	if( s.IsSaving())
	{
		std::map<Key,Value>::iterator iter = p.first->begin();
		while( iter != p.first->end() )
		{
			const Key &k = (iter->first);
			Value &v = iter->second;
			s&std::make_pair(&k, keyName);
			s&std::make_pair(&v, valueName);
			iter++;
		}
	}
	else
	{
        while( true )
        {
            Key k = Creator<Key>::Create();
            Value v = Creator<Value>::Create();
            s&std::make_pair(&k, keyName);
            if( s.GetLastLoad() == false )
            {
                Creator<Key>::Destroy( k );
                Creator<Value>::Destroy( v );
                break;
            }
            s&std::make_pair(&v, valueName);
            if( s.GetLastLoad() == false )
            {
                Creator<Key>::Destroy( k );
                Creator<Value>::Destroy( v );
                break;
            }
            p.first->insert( std::make_pair(k,v) );
        }
	}
	return s;
}

template <class T>
inline CSerialize &operator&(CSerialize &s, std::pair<std::vector<T>* , const char*> &p)
{
	
	if( s.IsSaving())
	{
        std::list<T>::iterator iter = p.first->begin();
        while( iter != p.first->end() )
        {
            T &obj = *iter;
            s&std::make_pair(&obj, p.second);
            iter++;
        }
	}
	else
	{
		while( true )
        {
            T obj = Creator<T>::Create();
            s&std::make_pair(&obj, p.second);
            if( s.GetLastLoad() == false )
            {
                Creator<T>::Destroy( obj );
                break;
            }
            p.first->push_back( obj );
        }
	}
	return s;
}

#define DECLARE_BASE_TYPE_SERIALIZE(TYPE)\
    template <>\
    inline CSerialize &operator&(CSerialize &s, std::pair<TYPE*, const char*> &p)\
    {\
		if( s.IsSaving())\
			s.Save(*(p.first), p.second);\
		else\
			s.Load(*(p.first), p.second);\
			return s;\
    }\
	template <>\
	inline CSerialize &operator&(CSerialize &s, std::pair<const TYPE*, const char*> &p)\
	{\
		TYPE *obj = const_cast<TYPE *>(p.first);\
		if( s.IsSaving())\
			s.Save(*(obj), p.second);\
		else\
			s.Load(*(obj), p.second);\
		return s;\
	}
#define DECLARE_BASE_TYPE_ARRAY_SERIALIZE(TYPE)\
	template <int ARRAY>\
	inline CSerialize &operator&(CSerialize &s, std::pair<TYPE (*)[ARRAY], const char*> &p)\
	{\
		int *array = *p.first;\
		for( int i=0; i<ARRAY; i++ )\
		{\
			char objNameBuf[128];\
			sprintf( objNameBuf, "%s%d", p.second,i );\
			const char *objName = objNameBuf;\
			if( s.IsSaving())\
				s.Save(array[i], objName);\
			else\
				s.Load(array[i], objName);\
		}\
		return s;\
	}

DECLARE_BASE_TYPE_SERIALIZE(int)
DECLARE_BASE_TYPE_SERIALIZE(float)
DECLARE_BASE_TYPE_SERIALIZE(char)
//DECLARE_BASE_TYPE_SERIALIZE(const char*)
DECLARE_BASE_TYPE_SERIALIZE(char*)
DECLARE_BASE_TYPE_SERIALIZE(unsigned char)
DECLARE_BASE_TYPE_SERIALIZE(int64)
DECLARE_BASE_TYPE_SERIALIZE(int16)
DECLARE_BASE_TYPE_SERIALIZE(uint16)
DECLARE_BASE_TYPE_SERIALIZE(uint32)
DECLARE_BASE_TYPE_SERIALIZE(uint64)
DECLARE_BASE_TYPE_SERIALIZE(long)
DECLARE_BASE_TYPE_SERIALIZE(unsigned long)

DECLARE_BASE_TYPE_ARRAY_SERIALIZE(int)
DECLARE_BASE_TYPE_ARRAY_SERIALIZE(float)
DECLARE_BASE_TYPE_ARRAY_SERIALIZE(unsigned char)
DECLARE_BASE_TYPE_ARRAY_SERIALIZE(int64)
DECLARE_BASE_TYPE_ARRAY_SERIALIZE(int16)
DECLARE_BASE_TYPE_ARRAY_SERIALIZE(uint16)
DECLARE_BASE_TYPE_ARRAY_SERIALIZE(uint32)
DECLARE_BASE_TYPE_ARRAY_SERIALIZE(uint64)
DECLARE_BASE_TYPE_ARRAY_SERIALIZE(long)
DECLARE_BASE_TYPE_ARRAY_SERIALIZE(unsigned long)

#endif